package Engine.AIUGame
{
	import flash.geom.Rectangle;

	public class AIObject extends AIBasic
	{
		//碰撞类型
		static public const LEFT:uint	= 0x0001;
		static public const RIGHT:uint	= 0x0010;
		static public const UP:uint		= 0x0100;
		static public const DOWN:uint	= 0x1000;
		
		static public const NONE:uint	= 0;
		static public const CEILING:uint= UP;  					//天花板
		static public const FLOOR:uint	= DOWN; 			//地板
		static public const WALL:uint	= LEFT | RIGHT; 		//墙
		static public const ANY:uint	= LEFT | RIGHT | UP | DOWN; //任何面
		
		
		static public const OVERLAP_BIAS:Number = 4;	//碰撞的最小间距
		
		
		public var immovable:Boolean; 		 //决定产生碰撞后 是否发生位置改变
		public var allowCollisions:uint; 	//决定物体的碰撞检查类型
		public var touching:uint;
		public var wasTouching:uint;
		
		public var mass:Number;
		public var elasticity:Number;
		
		
		public var moves:Boolean;
		
		//移动对象用到的参数
		public var velocity:AIPoint;  		//移动速度
		public var acceleration:AIPoint;	//加速度
		public var drag:AIPoint;			//阻力
		public var maxVelocity:AIPoint;	//最大的移动速度
		public var last:AIPoint;
		
		
		public var x:Number;
		public var y:Number;
		public var width:uint;
		public var height:uint;
		
		public function AIObject(X:Number=0,Y:Number=0,Width:Number=0,Height:Number=0)
		{
			super();
			
			x = X;
			y = Y;
			width = Width;
			height = Height;
			
			immovable = false;
			moves = true;
			
			allowCollisions = ANY; //默认是四面都要产生碰撞
			touching = NONE;
			wasTouching = NONE;
			
			mass = 1.0;
			elasticity = 0.0;
			
			last = new AIPoint(x,y);
			
			velocity = new AIPoint();
			acceleration = new AIPoint();
			drag = new AIPoint();
			maxVelocity = new AIPoint(10000,10000);
			
		}
		
		override public function preUpdate():void
		{
			last.x = x;
			last.y = y;	
		}
		
		override public function postUpdate():void
		{
			if(moves)
				updateMotion();
			
			wasTouching = touching;
			touching = NONE;
		}
		
		override public function destroy():void
		{
			velocity = null;
			acceleration = null;
			drag = null;
			maxVelocity = null;
			last = null;
		}
		
		
		/**
		 * 返回Object中心点
		 */
		public function getMidpoint(Point:AIPoint=null):AIPoint
		{
			if(Point == null)
				Point = new AIPoint();
			Point.x = x + width*0.5;
			Point.y = y + height*0.5;
			return Point;
		}
		
		/**
		 * 位置更新
		 */
		protected function updateMotion():void
		{
			var delta:Number;
			var velocityDelta:Number;
			
			velocityDelta = (AIGDate.computeVelocity(velocity.x,acceleration.x,drag.x,maxVelocity.x) - velocity.x)/2;
			velocity.x += velocityDelta;
			delta = velocity.x*AIGDate.elapsed;
			velocity.x += velocityDelta;
			x += delta;
			
			velocityDelta = (AIGDate.computeVelocity(velocity.y,acceleration.y,drag.y,maxVelocity.y) - velocity.y)/2;
			velocity.y += velocityDelta;
			delta = velocity.y*AIGDate.elapsed;
			velocity.y += velocityDelta;
			y += delta;
		}
		
		static public function separate(Object1:AIObject, Object2:AIObject):Boolean
		{
			var separatedX:Boolean = separateX(Object1,Object2);
			var separatedY:Boolean = separateY(Object1,Object2);
			return separatedX || separatedY;
		}
		
		/**
		 * 水平方向上的碰撞检测
		 */
		static public function separateX(Object1:AIObject, Object2:AIObject):Boolean
		{
			var obj1immovable:Boolean = Object1.immovable;
			var obj2immovable:Boolean = Object2.immovable;
			if(obj1immovable && obj2immovable)
				return false;
			
			var overlap:Number = 0;
			var obj1delta:Number = Object1.x - Object1.last.x;
			var obj2delta:Number = Object2.x - Object2.last.x;
			if(obj1delta != obj2delta)
			{
				var obj1deltaAbs:Number = (obj1delta > 0)?obj1delta:-obj1delta;
				var obj2deltaAbs:Number = (obj2delta > 0)?obj2delta:-obj2delta;
				var obj1rect:Rectangle = new Rectangle(Object1.x-((obj1delta > 0)?obj1delta:0),Object1.last.y,Object1.width+((obj1delta > 0)?obj1delta:-obj1delta),Object1.height);
				var obj2rect:Rectangle = new Rectangle(Object2.x-((obj2delta > 0)?obj2delta:0),Object2.last.y,Object2.width+((obj2delta > 0)?obj2delta:-obj2delta),Object2.height);
				if((obj1rect.x + obj1rect.width > obj2rect.x) && (obj1rect.x < obj2rect.x + obj2rect.width) && (obj1rect.y + obj1rect.height > obj2rect.y) && (obj1rect.y < obj2rect.y + obj2rect.height))
				{
					var maxOverlap:Number = obj1deltaAbs + obj2deltaAbs + OVERLAP_BIAS;
					
					if(obj1delta > obj2delta)
					{
						overlap = Object1.x + Object1.width - Object2.x;
						if((overlap > maxOverlap) || !(Object1.allowCollisions & RIGHT) || !(Object2.allowCollisions & LEFT))
							overlap = 0;
						else
						{
							Object1.touching |= RIGHT;
							Object2.touching |= LEFT;
						}
					}
					else if(obj1delta < obj2delta)
					{
						overlap = Object1.x - Object2.width - Object2.x;
						if((-overlap > maxOverlap) || !(Object1.allowCollisions & LEFT) || !(Object2.allowCollisions & RIGHT))
							overlap = 0;
						else
						{
							Object1.touching |= LEFT;
							Object2.touching |= RIGHT;
						}
					}
				}
			}
			
			if(overlap != 0)
			{
				var obj1v:Number = Object1.velocity.x;
				var obj2v:Number = Object2.velocity.x;
				
				if(!obj1immovable && !obj2immovable)
				{
					overlap *= 0.5;
					Object1.x = Object1.x - overlap;
					Object2.x += overlap;
					
					var obj1velocity:Number = Math.sqrt((obj2v * obj2v * Object2.mass)/Object1.mass) * ((obj2v > 0)?1:-1);
					var obj2velocity:Number = Math.sqrt((obj1v * obj1v * Object1.mass)/Object2.mass) * ((obj1v > 0)?1:-1);
					var average:Number = (obj1velocity + obj2velocity)*0.5;
					obj1velocity -= average;
					obj2velocity -= average;
					Object1.velocity.x = average + obj1velocity * Object1.elasticity;
					Object2.velocity.x = average + obj2velocity * Object2.elasticity;
				}
				else if(!obj1immovable)
				{
					Object1.x = Object1.x - overlap;
					Object1.velocity.x = obj2v - obj1v*Object1.elasticity;
				}
				else if(!obj2immovable)
				{
					Object2.x += overlap;
					Object2.velocity.x = obj1v - obj2v*Object2.elasticity;
				}
				return true;
			}
			else
				return false;
		}
		
		/**
		 * 垂直方向上的碰撞检测
		 */
		static public function separateY(Object1:AIObject, Object2:AIObject):Boolean
		{
			var obj1immovable:Boolean = Object1.immovable;
			var obj2immovable:Boolean = Object2.immovable;
			if(obj1immovable && obj2immovable)
				return false;
			
			var overlap:Number = 0;
			var obj1delta:Number = Object1.y - Object1.last.y;
			var obj2delta:Number = Object2.y - Object2.last.y;
			if(obj1delta != obj2delta)
			{
				var obj1deltaAbs:Number = (obj1delta > 0)?obj1delta:-obj1delta;
				var obj2deltaAbs:Number = (obj2delta > 0)?obj2delta:-obj2delta;
				var obj1rect:Rectangle = new Rectangle(Object1.x,Object1.y-((obj1delta > 0)?obj1delta:0),Object1.width,Object1.height+obj1deltaAbs);
				var obj2rect:Rectangle = new Rectangle(Object2.x,Object2.y-((obj2delta > 0)?obj2delta:0),Object2.width,Object2.height+obj2deltaAbs);
				if((obj1rect.x + obj1rect.width > obj2rect.x) && (obj1rect.x < obj2rect.x + obj2rect.width) && (obj1rect.y + obj1rect.height > obj2rect.y) && (obj1rect.y < obj2rect.y + obj2rect.height))
				{
					var maxOverlap:Number = obj1deltaAbs + obj2deltaAbs + OVERLAP_BIAS;
					
					if(obj1delta > obj2delta)
					{
						overlap = Object1.y + Object1.height - Object2.y;
						if((overlap > maxOverlap) || !(Object1.allowCollisions & DOWN) || !(Object2.allowCollisions & UP))
							overlap = 0;
						else
						{
							Object1.touching |= DOWN;
							Object2.touching |= UP;
						}
					}
					else if(obj1delta < obj2delta)
					{
						overlap = Object1.y - Object2.height - Object2.y;
						if((-overlap > maxOverlap) || !(Object1.allowCollisions & UP) || !(Object2.allowCollisions & DOWN))
							overlap = 0;
						else
						{
							Object1.touching |= UP;
							Object2.touching |= DOWN;
						}
					}
				}
			}
			
			if(overlap != 0)
			{
				var obj1v:Number = Object1.velocity.y;
				var obj2v:Number = Object2.velocity.y;
				
				if(!obj1immovable && !obj2immovable)
				{
					overlap *= 0.5;
					Object1.y = Object1.y - overlap;
					Object2.y += overlap;
					
					var obj1velocity:Number = Math.sqrt((obj2v * obj2v * Object2.mass)/Object1.mass) * ((obj2v > 0)?1:-1);
					var obj2velocity:Number = Math.sqrt((obj1v * obj1v * Object1.mass)/Object2.mass) * ((obj1v > 0)?1:-1);
					var average:Number = (obj1velocity + obj2velocity)*0.5;
					obj1velocity -= average;
					obj2velocity -= average;
					Object1.velocity.y = average + obj1velocity * Object1.elasticity;
					Object2.velocity.y = average + obj2velocity * Object2.elasticity;
				}
				else if(!obj1immovable)
				{
					Object1.y = Object1.y - overlap;
					Object1.velocity.y = obj2v - obj1v*Object1.elasticity;
					if(Object2.active && Object2.moves && (obj1delta > obj2delta))
						Object1.x += Object2.x - Object2.last.x;
				}
				else if(!obj2immovable)
				{
					Object2.y += overlap;
					Object2.velocity.y = obj1v - obj2v*Object2.elasticity;
					if(Object1.active && Object1.moves && (obj1delta < obj2delta))
						Object2.x += Object1.x - Object1.last.x;
				}
				return true;
			}
			else
				return false;
		}
	}
}